package com.mobibusbr.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import com.mobibusbr.interfaces.GenericDao;

public abstract class GenericDaoJPAImpl<T,PK extends Serializable> implements GenericDao<T, PK> {
	
	protected Class<?> entityClass;
	
	private static EntityManager instance;
	
	public static EntityManager getInstance() {
		if (instance == null) {
			EntityManagerFactory entity =  Persistence.createEntityManagerFactory("mobibusbr");
			instance = entity.createEntityManager();
		}
		return instance;
	}
	
	public GenericDaoJPAImpl() {
		ParameterizedType genericSuperClass = (ParameterizedType) getClass().getGenericSuperclass();
		this.entityClass = (Class<?>) genericSuperClass.getActualTypeArguments()[0];
	}	
	
	@Override
	public boolean adiciona(T obj){
		EntityManager manager = getInstance();
		boolean operacao = false;
		try {
			manager.getTransaction().begin();
			manager.persist(obj);
			manager.getTransaction().commit();
			operacao = true;	
		} catch (Exception e) {
			e.printStackTrace();
			manager.getTransaction().rollback();
			operacao = false;
		}		
		return operacao;
	}
	
	@Override
	public boolean atualiza(T obj){
		boolean operacao = false;
		EntityManager manager = getInstance();
		try {
			manager.getTransaction().begin();
			manager.merge(obj);
			manager.getTransaction().commit();
			operacao = true;			
		} catch (Exception e) {
			e.printStackTrace();
			manager.getTransaction().rollback();
			operacao = false;
		}
		return operacao;
	}
	
	@Override
	public boolean remover(PK id){
		boolean operacao = false;
		EntityManager manager = getInstance();
		try {
			manager.getTransaction().begin();
			Object obj = manager.find(entityClass, id);
			manager.remove(obj);
			manager.getTransaction().commit();
			operacao = true;
			
		} catch (Exception e) {
			e.printStackTrace();
			manager.getTransaction().rollback();
			operacao = false;
		}
		return operacao;
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public T busca(PK id){
		Object obj = null;
		EntityManager manager = getInstance();
		try {
			manager.getTransaction().begin();
			obj = manager.find(entityClass, id);
			manager.getTransaction().commit();
			
		} catch (Exception e) {
			e.printStackTrace();
			manager.getTransaction().rollback();
		}
		return (T) obj;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<?> getLista(){
		EntityManager manager = getInstance();
		CriteriaBuilder cb = manager.getCriteriaBuilder();
		CriteriaQuery<T> c = (CriteriaQuery<T>) cb.createQuery(entityClass);
		Root<T> root = (Root<T>) c.from(entityClass);
		c.select(root);
		
		TypedQuery<T> query = manager.createQuery(c);
		List<?> lista = query.getResultList();
		return lista;
	}

}